home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / documents / video / lurker / ij / ij.c next >
Encoding:
C/C++ Source or Header  |  1996-11-11  |  30.9 KB  |  1,127 lines

  1. /*
  2.  * ij.c - device-independent input jacks for VL
  3.  *  
  4.  * WARNING this version has not been tested for all jacks for
  5.  * all devices.
  6.  */
  7.  
  8. #include "ij.h"
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <assert.h>
  13.  
  14. /* devices ------------------------------------------------------------- */
  15.  
  16. typedef struct ijdevice
  17. {
  18.   int (*setup)(IJhandle me, VLNode drain_node); /* returns TRUE on success */
  19.   char *(*getjackname)(IJhandle me, int idx);
  20.   int (*mapidx)(IJhandle me, int idx, int *ret_idx_base);
  21.   int (*configurepath)(IJhandle me, int idx,
  22.                        VLNode source_node, VLNode drain_node, VLPath path,
  23.                        int node_number, int *ret_idx); /*returns 0 on success*/
  24.   int (*isjackcontrol)(IJhandle me, VLControlType type);
  25.   void (*teardown)(IJhandle me);
  26. } ijdevice;
  27.  
  28. /* handle ------------------------------------------------------------- */
  29.  
  30. typedef struct _IJhandle
  31. {
  32.   VLServer svr;
  33.   VLDev device;
  34.  
  35.   ijdevice *ijd;
  36.   void *dev_specific;
  37.  
  38.   int num_jacks;
  39.   char *device_name;
  40.   
  41. } _IJhandle;
  42.  
  43. /* util ------------------------------------------------------------- */
  44.  
  45. /*
  46.  * get video source node number of the device's default source
  47.  */
  48. int getdefaultsource(IJhandle me)
  49. {
  50.   VLNode devNode;
  51.   VLPath controlPath;
  52.   VLControlValue val;
  53.   val.intVal = -1;
  54.   
  55.   if (-1 != (devNode = vlGetNode(me->svr, VL_DEVICE, 0, VL_ANY)) &&
  56.       -1 != (controlPath = vlCreatePath(me->svr, me->device, 
  57.                                         devNode, devNode))&&
  58.       -1 != vlSetupPaths(me->svr, &controlPath, 1, VL_SHARE, VL_READ_ONLY) &&
  59.       -1 != vlGetControl(me->svr, controlPath, devNode, 
  60.                          VL_DEFAULT_SOURCE, &val) &&
  61.       -1 != vlDestroyPath(me->svr, controlPath))
  62.     return val.intVal;
  63.  
  64.   return -1;
  65. }
  66.  
  67. /* vino ------------------------------------------------------------- */
  68.  
  69. int vinosetup(IJhandle me, VLNode drain_node)
  70. {
  71.   me->num_jacks = 3;
  72.   me->device_name = "VINO Video";
  73.   return TRUE;
  74. }
  75. char *vinogetjackname(IJhandle me, int idx)
  76. {
  77.   switch (idx)
  78.     {
  79.     case 0: return "Composite";
  80.     case 1: return "S-Video";
  81.     case 2: return "Indycam/601 Serial Digital";
  82.     default: return NULL;
  83.     }
  84. }
  85.  
  86. #define VINO_ANALOG_NODE 1
  87. #define VINO_DIGITAL_NODE 0
  88.  
  89. #define VINO_COMPOSITE_MUXSWITCH 0
  90. #define VINO_SVIDEO_MUXSWITCH 1
  91.  
  92. /* map idx to node number.  idx is between 0 and me->num_jacks-1. */
  93. int vinomapidx(IJhandle me, int idx, int *ret_idx_base)
  94. {
  95.   int node_number;
  96.   
  97.   switch (idx)
  98.     {
  99.     case 0:
  100.     case 1:
  101.       node_number = VINO_ANALOG_NODE;  break;
  102.     case 2:
  103.       node_number = VINO_DIGITAL_NODE; break;
  104.     default:
  105.       return -1;
  106.     }
  107.  
  108.   if (ret_idx_base) *ret_idx_base = 0; /* not used for vino */
  109.   return node_number;
  110. }
  111.  
  112. int vinoconfigurepath(IJhandle me, int idx,
  113.                       VLNode source_node, VLNode drain_node, VLPath path,
  114.                       int node_number, int *ret_idx)
  115. {
  116.   VLControlValue val;
  117.   int returned_idx;
  118.  
  119.   /* -- perform node-number-specific operations */
  120.   switch (node_number)
  121.     {
  122.     case VINO_ANALOG_NODE:
  123.       {
  124.         if (idx==VL_ANY)
  125.           {
  126.             if (vlGetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) 
  127.                 < 0)
  128.               { vlDestroyPath(me->svr, path); return -1; }
  129.             switch (val.intVal)
  130.               {
  131.               case VINO_COMPOSITE_MUXSWITCH: returned_idx = 0; break;
  132.               case VINO_SVIDEO_MUXSWITCH:    returned_idx = 1; break;
  133.               }
  134.           }
  135.         else
  136.           {
  137.             returned_idx = idx;
  138.             switch (idx)
  139.               {
  140.               case 0: val.intVal = VINO_COMPOSITE_MUXSWITCH; break;
  141.               case 1: val.intVal = VINO_SVIDEO_MUXSWITCH;    break;
  142.               }
  143.             if (vlSetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) 
  144.                 < 0)
  145.               { vlDestroyPath(me->svr, path); return -1; }
  146.           }
  147.       }
  148.       break;
  149.       
  150.     case VINO_DIGITAL_NODE:
  151.       {
  152.         /* XXX need to set VL_TIMING differently for 601 option? */
  153.         returned_idx = 2;
  154.       }
  155.       break;
  156.     }
  157.  
  158.   if (ret_idx) *ret_idx = returned_idx;
  159.   return 0;
  160. }
  161.  
  162. int vinoisjackcontrol(IJhandle me, VLControlType type)
  163. {
  164.   return (type==VL_MUXSWITCH)||(type==VL_FORMAT);
  165. }
  166.  
  167. ijdevice vinodev = { vinosetup, vinogetjackname, 
  168.                      vinomapidx, vinoconfigurepath, 
  169.                      vinoisjackcontrol, NULL };
  170.  
  171. /* ev1 ------------------------------------------------------------- */
  172.  
  173. /* junior and on-board have 3 analog jacks, ABOB has 8 jacks */
  174. #define JUNIOR_ANALOG 3
  175. #define ABOB_ANALOG   8
  176.  
  177. /* DBOB has 2 jacks that we support.  we don't support serial or
  178.  * parallel digital in 2 because it is often not accessible 
  179.  * if the user happens to have a cosmo1 board also plugged in--it's
  180.  * not worth the documentation/usability nightmare.
  181.  */
  182. #define DBOB          2
  183. #define NO_DBOB       0
  184.  
  185. /* indycam plugs into the same place as DBOB and acts as one input */
  186. #define INDYCAM       1
  187. #define NO_INDYCAM    0
  188.  
  189. typedef struct ev1data
  190. {
  191.   int num_analog_jacks;  /* JUNIOR_ANALOG or ABOB_ANALOG */
  192.   int num_dbob_jacks;    /* DBOB or NO_DBOB */
  193.   int num_indycam_jacks; /* INDYCAM or NO_INDYCAM */
  194.  
  195.   int analog_base;
  196.   int dbob_base;
  197.   int indycam_base;
  198. } ev1data;
  199.  
  200. #include <invent.h>
  201. #include <dmedia/vl_ev1.h>
  202.  
  203. int ev1setup(IJhandle me, VLNode drain_node)
  204. {
  205.   ev1data *ev1 = me->dev_specific = malloc(sizeof(ev1data));
  206.   inventory_t cpu, vid;
  207.   inv_state_t *foo = NULL;
  208.   inventory_t *inv;
  209.  
  210.   if (!ev1)
  211.     return FALSE;
  212.  
  213.   cpu.inv_class = -1;
  214.   vid.inv_class = -1;
  215.  
  216.   /* search for CPU and video in inventory */
  217.  
  218.   if (setinvent_r(&foo) < 0)
  219.     return FALSE;
  220.   
  221.   while ((inv = getinvent_r(foo)) &&
  222.          (vid.inv_class == -1 || cpu.inv_class == -1))
  223.     {
  224.       if (inv->inv_class == INV_VIDEO &&
  225.           (inv->inv_type == INV_VIDEO_EXPRESS ||
  226.            inv->inv_type == INV_VIDEO_INDY ||
  227.            inv->inv_type == INV_VIDEO_INDY_601))
  228.         vid = *inv;
  229.       
  230.       else if (inv->inv_class == INV_PROCESSOR &&
  231.                inv->inv_type == INV_CPUBOARD)
  232.         cpu = *inv;
  233.     }
  234.   
  235.   endinvent_r(foo);
  236.   
  237.   if (vid.inv_class == -1 || cpu.inv_class == -1)
  238.     {
  239.       free(ev1);
  240.       me->dev_specific = NULL;
  241.       return FALSE;
  242.     }
  243.   
  244.   if (vid.inv_type == INV_VIDEO_INDY)
  245.     {
  246.       /* Indy Video */
  247.       ev1->num_analog_jacks = JUNIOR_ANALOG;
  248.       ev1->num_dbob_jacks = NO_DBOB;
  249.       ev1->num_indycam_jacks = NO_INDYCAM;
  250.       me->device_name = "Indy Video";
  251.     }
  252.   else if (vid.inv_type == INV_VIDEO_INDY_601)
  253.     {
  254.       /* Indy Video 601 */
  255.       ev1->num_analog_jacks = JUNIOR_ANALOG;
  256.       /* vid.inv_state & INV_GALILEO_DBOB is not set for Indy Video 601 */
  257.       ev1->num_dbob_jacks = DBOB;
  258.       ev1->num_indycam_jacks = NO_INDYCAM;
  259.       me->device_name = "Indy Video 601";
  260.     }
  261.   else if (vid.inv_type == INV_VIDEO_EXPRESS)
  262.     {
  263.       /* an Indigo or Indigo2 ev1 */
  264.  
  265.       if (cpu.inv_state == INV_IP12BOARD ||
  266.           cpu.inv_state == INV_IP20BOARD)
  267.         {
  268.           /* Indigo Video */
  269.           ev1->num_analog_jacks = ABOB_ANALOG;
  270.           if (vid.inv_state & INV_GALILEO_DBOB)
  271.             ev1->num_dbob_jacks = DBOB;
  272.           if (vid.inv_state & INV_GALILEO_INDY_CAM)
  273.             ev1->num_indycam_jacks = INDYCAM;
  274.           me->device_name = "Indigo Video";
  275.         }
  276.       else
  277.         {
  278.           /* an Indigo2 board */
  279.           
  280.           if (vid.inv_state & INV_GALILEO_JUNIOR)
  281.             {
  282.               /* a junior board -- Indigo2 Video 
  283.                *                or Indigo2 Video for Impact
  284.                */
  285.               ev1->num_analog_jacks = JUNIOR_ANALOG;
  286.               ev1->num_dbob_jacks = NO_DBOB;
  287.               if (vid.inv_state & INV_GALILEO_INDY_CAM)
  288.                 ev1->num_indycam_jacks = INDYCAM;
  289.               me->device_name = "Indigo2 Video";
  290.             }
  291.           else
  292.             {
  293.               /* Galileo Video */
  294.               ev1->num_analog_jacks = ABOB_ANALOG;
  295.               if (vid.inv_state & INV_GALILEO_DBOB)
  296.                 ev1->num_dbob_jacks = DBOB;
  297.               if (vid.inv_state & INV_GALILEO_INDY_CAM)
  298.                 ev1->num_indycam_jacks = INDYCAM;
  299.               me->device_name = "Galileo Video";
  300.             }
  301.         }
  302.     }
  303.   else /* video not found, or unrecognized ev1 board */
  304.     return FALSE;
  305.  
  306.   me->num_jacks = 
  307.     ev1->num_analog_jacks + ev1->num_dbob_jacks + ev1->num_indycam_jacks;
  308.  
  309.   ev1->analog_base = 0;
  310.   ev1->dbob_base = ev1->num_analog_jacks;
  311.   ev1->indycam_base = ev1->num_analog_jacks + ev1->num_dbob_jacks;
  312.  
  313.   return TRUE;
  314. }
  315. char *ev1getjackname(IJhandle me, int idx)
  316. {
  317.   ev1data *ev1 = me->dev_specific;
  318.   
  319.   if (idx+ev1->analog_base < ev1->num_analog_jacks)
  320.     {
  321.       idx -= ev1->analog_base;
  322.  
  323.       /* analog jack */
  324.       if (ev1->num_analog_jacks == ABOB_ANALOG)
  325.         switch (idx)
  326.           {
  327.           case 0: return "Composite 1";
  328.           case 1: return "Composite 2";
  329.           case 2: return "Composite 3";
  330.           case 3: return "S-Video (Y/C) 1";
  331.           case 4: return "S-Video (Y/C) 2";
  332.           case 5: return "S-Video (Y/C) 3";
  333.           case 6: return "Component (Y, R-Y, B-Y) 1";
  334.           case 7: return "Component (Y, R-Y, B-Y) 2";
  335.           }
  336.       else /* JUNIOR_ANALOG */
  337.         switch (idx)
  338.           {
  339.           case 0: return "Composite 1";
  340.           case 1: return "Composite 2"; 
  341.           case 2: return "S-Video";
  342.           }
  343.       return NULL;
  344.     }
  345.   
  346.   if (idx-ev1->dbob_base < ev1->num_dbob_jacks)
  347.     {
  348.       idx -= ev1->dbob_base;
  349.  
  350.       /* digital jack */
  351.       switch (idx)
  352.         {
  353.         case 0: return "601 Serial Digital 1";
  354.         case 1: return "601 Parallel Digital 1";
  355.         }
  356.       return NULL;
  357.     }
  358.  
  359.   if (idx-ev1->indycam_base < ev1->num_indycam_jacks)
  360.     {
  361.       idx -= ev1->indycam_base;
  362.       return "IndyCam";
  363.     }
  364.  
  365.   return NULL;
  366. }
  367.  
  368. #define EV1_ANALOG_NODE   0
  369. #define EV1_DIGITAL1_NODE 1
  370.  
  371. #define EV1_ABOB_COMPOSITE1_MUXSWITCH 3
  372. #define EV1_ABOB_COMPOSITE2_MUXSWITCH 4
  373. #define EV1_ABOB_COMPOSITE3_MUXSWITCH 5
  374. #define EV1_ABOB_YC1_MUXSWITCH 0
  375. #define EV1_ABOB_YC2_MUXSWITCH 1
  376. #define EV1_ABOB_YC3_MUXSWITCH 2
  377. #define EV1_ABOB_COMPONENT1_MUXSWITCH 6
  378. #define EV1_ABOB_COMPONENT2_MUXSWITCH 7
  379.  
  380. #define EV1_JUNIOR_COMPOSITE1_MUXSWITCH 3
  381. #define EV1_JUNIOR_COMPOSITE2_MUXSWITCH 4
  382. #define EV1_JUNIOR_YC1_MUXSWITCH 1
  383.  
  384. #define EV1_DBOB_SERIAL_DIGITAL 1
  385. #define EV1_DBOB_PARALLEL_DIGITAL 0
  386.  
  387. /* map idx to node number.  idx is between 0 and me->num_jacks-1. */
  388. int ev1mapidx(IJhandle me, int idx, int *ret_idx_base)
  389. {
  390.   int node_number;
  391.   int idx_base;
  392.   ev1data *ev1 = me->dev_specific;
  393.  
  394.   if (idx-ev1->analog_base < ev1->num_analog_jacks)
  395.     {
  396.       idx_base = ev1->analog_base;
  397.       node_number = EV1_ANALOG_NODE;
  398.     }
  399.   else if (idx-ev1->dbob_base < ev1->num_dbob_jacks)
  400.     {
  401.       idx_base = ev1->dbob_base;
  402.       node_number = EV1_DIGITAL1_NODE;
  403.     }
  404.   else if (idx-ev1->indycam_base < ev1->num_indycam_jacks)
  405.     {
  406.       idx_base = ev1->indycam_base;
  407.       node_number = EV1_DIGITAL1_NODE;
  408.     }
  409.   else
  410.     return -1;
  411.  
  412.   if (ret_idx_base) *ret_idx_base = idx_base;
  413.   return node_number;
  414. }
  415.  
  416. int ev1configurepath(IJhandle me, int idx,
  417.                      VLNode source_node, VLNode drain_node, VLPath path,
  418.                      int node_number, int *ret_idx)
  419. {
  420.   VLControlValue val;
  421.   int returned_idx;
  422.   int idx_base=-1;
  423.   ev1data *ev1 = me->dev_specific;
  424.  
  425.   /* -- compute idx_base if idx != VL_ANY */
  426.   if (idx != VL_ANY)
  427.     {
  428.       node_number = ev1mapidx(me, idx, &idx_base);
  429.       assert(node_number >= 0);
  430.       assert(idx_base >= 0);
  431.       idx -= idx_base;
  432.     }
  433.   
  434.   /* -- perform node-number-specific operations */
  435.   switch (node_number)
  436.     {
  437.     case EV1_ANALOG_NODE:
  438.       if (idx == VL_ANY)
  439.         {
  440.           idx_base = ev1->analog_base;
  441.  
  442.           if (vlGetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0)
  443.             { vlDestroyPath(me->svr, path);  return -1; }
  444.           
  445.           if (ev1->num_analog_jacks == ABOB_ANALOG)
  446.             switch (val.intVal)
  447.               {
  448.               case EV1_ABOB_COMPOSITE1_MUXSWITCH: returned_idx = 0; break;
  449.               case EV1_ABOB_COMPOSITE2_MUXSWITCH: returned_idx = 1; break;
  450.               case EV1_ABOB_COMPOSITE3_MUXSWITCH: returned_idx = 2; break;
  451.               case EV1_ABOB_YC1_MUXSWITCH:        returned_idx = 3; break;
  452.               case EV1_ABOB_YC2_MUXSWITCH:        returned_idx = 4; break;
  453.               case EV1_ABOB_YC3_MUXSWITCH:        returned_idx = 5; break;
  454.               case EV1_ABOB_COMPONENT1_MUXSWITCH: returned_idx = 6; break;
  455.               case EV1_ABOB_COMPONENT2_MUXSWITCH: returned_idx = 7; break;
  456.               }
  457.           else /* JUNIOR_ANALOG */
  458.             switch (val.intVal)
  459.               {
  460.               case EV1_JUNIOR_COMPOSITE1_MUXSWITCH: returned_idx = 0; break;
  461.               case EV1_JUNIOR_COMPOSITE2_MUXSWITCH: returned_idx = 1; break;
  462.               case EV1_JUNIOR_YC1_MUXSWITCH:        returned_idx = 2; break;
  463.               }
  464.         }
  465.       else
  466.         {
  467.           returned_idx = idx;
  468.  
  469.           if (ev1->num_analog_jacks == ABOB_ANALOG)
  470.             switch (idx)
  471.               {
  472.               case 0: val.intVal = EV1_ABOB_COMPOSITE1_MUXSWITCH; break;
  473.               case 1: val.intVal = EV1_ABOB_COMPOSITE2_MUXSWITCH; break;
  474.               case 2: val.intVal = EV1_ABOB_COMPOSITE3_MUXSWITCH; break;
  475.               case 3: val.intVal = EV1_ABOB_YC1_MUXSWITCH; break;
  476.               case 4: val.intVal = EV1_ABOB_YC2_MUXSWITCH; break;
  477.               case 5: val.intVal = EV1_ABOB_YC3_MUXSWITCH; break;
  478.               case 6: val.intVal = EV1_ABOB_COMPONENT1_MUXSWITCH; break;
  479.               case 7: val.intVal = EV1_ABOB_COMPONENT2_MUXSWITCH; break;
  480.               }
  481.           else /* JUNIOR_ANALOG */
  482.             switch (idx)
  483.               {
  484.               case 0: val.intVal = EV1_JUNIOR_COMPOSITE1_MUXSWITCH; break;
  485.               case 1: val.intVal = EV1_JUNIOR_COMPOSITE2_MUXSWITCH; break;
  486.               case 2: val.intVal = EV1_JUNIOR_YC1_MUXSWITCH; break;
  487.               }
  488.           
  489.           if (vlSetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0)
  490.             { vlDestroyPath(me->svr, path); return -1; }
  491.         }
  492.       break;
  493.     case EV1_DIGITAL1_NODE: /* indycam or dbob (not both) */
  494.       if (idx == VL_ANY)
  495.         {
  496.           if (ev1->num_indycam_jacks == INDYCAM)
  497.             {
  498.               idx_base = ev1->indycam_base;
  499.               returned_idx = 0;
  500.             }
  501.           else
  502.             {
  503.               idx_base = ev1->dbob_base;
  504.               if (vlGetControl(me->svr, path, source_node, 
  505.                                VL_EV1_DBOB_INPUT1, &val) < 0)
  506.                 { vlDestroyPath(me->svr, path);  return -1; }
  507.               
  508.               switch (val.intVal)
  509.                 {
  510.                 case EV1_DBOB_SERIAL_DIGITAL:   returned_idx = 0; break;
  511.                 case EV1_DBOB_PARALLEL_DIGITAL: returned_idx = 1; break;
  512.                 }
  513.             }
  514.         }
  515.       else
  516.         {
  517.           returned_idx = idx;
  518.  
  519.           /* XXX need to set VL_EV1_DBOB_INPUT1 for indycam? */
  520.           if (ev1->num_indycam_jacks == NO_INDYCAM)
  521.             {
  522.               switch (idx)
  523.                 {
  524.                 case 0: val.intVal = EV1_DBOB_SERIAL_DIGITAL;   break;
  525.                 case 1: val.intVal = EV1_DBOB_PARALLEL_DIGITAL; break;
  526.                 }
  527.               if (vlSetControl(me->svr, path, source_node, 
  528.                                VL_EV1_DBOB_INPUT1, &val) < 0)
  529.                 { vlDestroyPath(me->svr, path); return -1; }
  530.             }
  531.         }
  532.       break;
  533.     }
  534.  
  535.   assert(idx_base != -1);
  536.   if (ret_idx) *ret_idx = returned_idx + idx_base;
  537.   return 0;
  538. }
  539. int ev1isjackcontrol(IJhandle me, VLControlType type)
  540. {
  541.   return (type==VL_MUXSWITCH);
  542. }
  543. void ev1teardown(IJhandle me)
  544. {
  545.   ev1data *ev1 = me->dev_specific;
  546.   free(ev1);
  547.   me->dev_specific = NULL;
  548. }
  549.  
  550. ijdevice ev1dev = { ev1setup, ev1getjackname, 
  551.                     ev1mapidx, ev1configurepath, 
  552.                     ev1isjackcontrol, ev1teardown };
  553.  
  554. /* impact ------------------------------------------------------------- */
  555.  
  556. /*
  557.  * "impact" is a single VL device that, underneath, could be:
  558.  *   - Impact Video only
  559.  *   - Impact Compression only
  560.  *   - Impact Video and Impact Compression together
  561.  *
  562.  * Impact Video will show up as input node numbers 0, 1, and 2,
  563.  * and Impact Compression will show up as input node number 4.
  564.  */
  565.  
  566. #define NO_EV3 0
  567. #define EV3 3
  568.  
  569. #define NO_COSMO2 0
  570. #define COSMO2 2
  571.  
  572. typedef struct impactdata
  573. {
  574.   int num_ev3_jacks;     /* Impact Video jacks: NO_EV3 or EV3 */
  575.   int num_cosmo2_jacks;  /* Impact Compression jacks: NO_COSMO2 or COSMO2 */
  576.  
  577.   int ev3_base;
  578.   int cosmo2_base;
  579. } impactdata;
  580.  
  581. int impactsetup(IJhandle me, VLNode drain_node)
  582. {
  583.   int dv, nd;
  584.   VLDevList devlist;
  585.   impactdata *iv = me->dev_specific = malloc(sizeof(impactdata));
  586.  
  587.   if (vlGetDeviceList(me->svr, &devlist) < 0)
  588.     { free(iv); return FALSE; }
  589.   for (dv=0; dv < (int)devlist.numDevices; dv++)
  590.     if (devlist.devices[dv].dev == me->device)
  591.       break;
  592.   assert(dv != (int)devlist.numDevices);
  593.  
  594.   iv->num_ev3_jacks = NO_EV3;
  595.   iv->num_cosmo2_jacks = NO_COSMO2;
  596.  
  597.   for(nd=0; nd < devlist.devices[dv].numNodes; nd++)
  598.     {
  599.       int node_number = devlist.devices[dv].nodes[nd].number;
  600.       if (node_number == 0) /* one of ev3's nodes */
  601.         iv->num_ev3_jacks = EV3;
  602.       else if (node_number == 4) /* one of cosmo2's nodes */
  603.         iv->num_cosmo2_jacks = COSMO2;
  604.     }
  605.   /* you are not supposed to free a VLDevList */
  606.   
  607.   me->num_jacks = iv->num_ev3_jacks + iv->num_cosmo2_jacks;
  608.   
  609.   iv->ev3_base = 0;
  610.   iv->cosmo2_base = iv->num_ev3_jacks;
  611.  
  612.   /* one or the other must be there!! */
  613.   assert(iv->num_ev3_jacks==EV3 || iv->num_cosmo2_jacks==COSMO2);
  614.  
  615.   if (iv->num_ev3_jacks==EV3 && iv->num_cosmo2_jacks==NO_COSMO2)
  616.     me->device_name = "Impact Video";
  617.   else if (iv->num_ev3_jacks==NO_EV3 && iv->num_cosmo2_jacks==COSMO2)
  618.     me->device_name = "Impact Compression";
  619.   else
  620.     me->device_name = "Impact Video/Impact Compression";
  621.  
  622.   return TRUE;
  623. }
  624. char *impactgetjackname(IJhandle me, int idx)
  625. {
  626.   impactdata *iv = me->dev_specific;
  627.  
  628.   if (idx-iv->ev3_base < iv->num_ev3_jacks)
  629.     {
  630.       idx -= iv->ev3_base;
  631.       switch (idx)
  632.         {
  633.         case 0: return "601 Serial Digital 1";
  634.         case 1: return "601 Serial Digital 2";
  635.         case 2: return "601 Serial Digital Dual-Link";
  636.         }
  637.       return NULL;
  638.     }
  639.  
  640.   if (idx-iv->cosmo2_base < iv->num_cosmo2_jacks)
  641.     {
  642.       idx -= iv->cosmo2_base;
  643.       switch (idx)
  644.         {
  645.         case 0: return "Composite";
  646.         case 1: return "S-Video";
  647.         }
  648.       return NULL;
  649.     }
  650.   
  651.   return NULL;
  652. }
  653.  
  654. #define IMPACT_SERIAL1_NODE 0
  655. #define IMPACT_SERIAL2_NODE 1
  656. #define IMPACT_DUAL_LINK_NODE  2
  657. #define IMPACT_COSMO2_NODE  4
  658.  
  659. #define IMPACT_COMPOSITE_MUXSWITCH 0
  660. #define IMPACT_SVIDEO_MUXSWITCH 1
  661.  
  662. /* map idx to node number.  idx is between 0 and me->num_jacks-1. */
  663. int impactmapidx(IJhandle me, int idx, int *ret_idx_base)
  664. {
  665.   int node_number;
  666.   int idx_base;
  667.   impactdata *iv = me->dev_specific;
  668.  
  669.   if (idx-iv->ev3_base < iv->num_ev3_jacks)
  670.     {
  671.       idx_base = iv->ev3_base;
  672.       idx -= idx_base;
  673.       switch (idx)
  674.         {
  675.         case 0: node_number = IMPACT_SERIAL1_NODE; break;
  676.         case 1: node_number = IMPACT_SERIAL2_NODE; break;
  677.         case 2: node_number = IMPACT_DUAL_LINK_NODE; break;
  678.         }
  679.     }
  680.   else if (idx-iv->cosmo2_base < iv->num_cosmo2_jacks)
  681.     {
  682.       idx_base = iv->cosmo2_base;
  683.       node_number = IMPACT_COSMO2_NODE;
  684.     }
  685.   else
  686.     return -1;
  687.  
  688.   if (ret_idx_base) *ret_idx_base = idx_base;
  689.   return node_number;
  690. }
  691.  
  692. int impactconfigurepath(IJhandle me, int idx,
  693.                            VLNode source_node, VLNode drain_node, VLPath path,
  694.                            int node_number, int *ret_idx)
  695. {
  696.   VLControlValue val;
  697.   int returned_idx;
  698.   int idx_base=-1;
  699.   impactdata *iv = me->dev_specific;
  700.  
  701.   /* -- compute idx_base if idx != VL_ANY */
  702.   if (idx != VL_ANY)
  703.     {
  704.       node_number = impactmapidx(me, idx, &idx_base);
  705.       assert(node_number >= 0);
  706.       assert(idx_base >= 0);
  707.       idx -= idx_base;
  708.     }
  709.   
  710.   /* -- perform node-number-specific operations */
  711.   switch (node_number)
  712.     {
  713.     case IMPACT_SERIAL1_NODE:
  714.       idx_base = iv->ev3_base;
  715.       returned_idx = 0;
  716.       break; 
  717.     case IMPACT_SERIAL2_NODE:
  718.       idx_base = iv->ev3_base;
  719.       returned_idx = 1;
  720.       break; 
  721.     case IMPACT_DUAL_LINK_NODE:
  722.       idx_base = iv->ev3_base;
  723.       returned_idx = 2;
  724.       break; 
  725.     case IMPACT_COSMO2_NODE:
  726.       if (idx == VL_ANY)
  727.         {
  728.           idx_base = iv->cosmo2_base;
  729.           if (vlGetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0)
  730.             { vlDestroyPath(me->svr, path);  return -1; }
  731.           switch (val.intVal)
  732.             {
  733.             case IMPACT_COMPOSITE_MUXSWITCH: returned_idx = 0; break;
  734.             case IMPACT_SVIDEO_MUXSWITCH:    returned_idx = 1; break;
  735.             }
  736.         }
  737.       else
  738.         {
  739.           returned_idx = idx;
  740.           switch (idx)
  741.             {
  742.             case 0: val.intVal = IMPACT_COMPOSITE_MUXSWITCH; break;
  743.             case 1: val.intVal = IMPACT_SVIDEO_MUXSWITCH;    break;
  744.             }
  745.           if (vlSetControl(me->svr, path, source_node, VL_MUXSWITCH, &val) < 0)
  746.             { vlDestroyPath(me->svr, path); return -1; }
  747.         }
  748.       break;
  749.     }
  750.  
  751.   assert(idx_base != -1);
  752.   if (ret_idx) *ret_idx = returned_idx + idx_base;
  753.   return 0;
  754. }
  755.  
  756. int impactisjackcontrol(IJhandle me, VLControlType type)
  757. {
  758.   return (type==VL_MUXSWITCH);
  759. }
  760.  
  761. void impactteardown(IJhandle me)
  762. {
  763.   impactdata *iv = me->dev_specific;
  764.   free(iv);
  765.   me->dev_specific = NULL;
  766. }
  767.  
  768. ijdevice impactdev = 
  769. { impactsetup, impactgetjackname, 
  770.   impactmapidx, impactconfigurepath,
  771.   impactisjackcontrol, impactteardown };
  772.  
  773. /* sirius ------------------------------------------------------------- */
  774.  
  775. int siriussetup(IJhandle me, VLNode drain_node)
  776. {
  777.   /* probe for serial digital i/o option */
  778.   VLControlInfo *info;
  779.   int i;
  780.   VLNode node = vlGetNode(me->svr, VL_SRC, VL_VIDEO, 0 /* digital in 1 */ );
  781.   VLPath path = vlCreatePath(me->svr, me->device, node, drain_node);
  782.   if (node < 0 || path < 0) return FALSE;
  783.  
  784.   /* argh! have to set up path for vlGetControlInfo to work! */
  785.   if (vlSetupPaths(me->svr, (VLPathList)&path, 1, 
  786.                    VL_READ_ONLY, VL_READ_ONLY) < 0)
  787.     { vlDestroyPath(me->svr, path); return FALSE; }
  788.   
  789.   /* search the VL_FORMAT parameter for any serial digital setting */
  790.   info = vlGetControlInfo(me->svr, path, node, VL_FORMAT);
  791.   if (!info) { vlDestroyPath(me->svr, path); return FALSE; }
  792.   
  793.   for(i=0; i < info->numItems; i++)
  794.     if (info->itemList[i].value == 8 /* serial 4:2:2:4 */)
  795.       break;
  796.   
  797.   if (i == info->numItems)
  798.     me->num_jacks = 10; /* no serial digital at all */
  799.   else
  800.     me->num_jacks = 14; /* full serial digital (single/dual, 1/2) */
  801.   
  802.   me->device_name = "Sirius Video";
  803.  
  804.   if (vlFreeControlInfo(me->svr, info) < 0)
  805.     { vlDestroyPath(me->svr, path); return FALSE; }
  806.   
  807.   if (vlDestroyPath(me->svr, path) < 0)
  808.     return FALSE;
  809.  
  810.   return TRUE;
  811. }
  812. char *siriusgetjackname(IJhandle me, int idx)
  813. {
  814.   switch (idx)
  815.     {
  816.     case 0:  return "RGB";
  817.     case 1:  return "YUV";
  818.     case 2:  return "Betacam";
  819.     case 3:  return "M-II";
  820.     case 4:  return "Composite";
  821.     case 5:  return "S-Video";
  822.     case 6:  return "601 Parallel Digital 1: 4:2:2:4";
  823.     case 7:  return "601 Parallel Digital 2: 4:2:2:4";
  824.     case 8:  return "601 Parallel Digital 1: 4:4:4:4";
  825.     case 9:  return "601 Parallel Digital 2: 4:4:4:4";
  826.     case 10: return "601 Serial Digital 1: 4:2:2:4";
  827.     case 11: return "601 Serial Digital 2: 4:2:2:4";
  828.     case 12: return "601 Serial Digital 1: 4:4:4:4";
  829.     case 13: return "601 Serial Digital 2: 4:4:4:4";
  830.     }
  831. }
  832.  
  833. #define SIRIUS_DIGITAL1_NODE 0
  834. #define SIRIUS_DIGITAL2_NODE 1
  835. #define SIRIUS_ANALOG_NODE   2
  836.  
  837. /* map idx to node number.  idx is between 0 and me->num_jacks-1. */
  838. int siriusmapidx(IJhandle me, int idx, int *ret_idx_base)
  839. {
  840.   int node_number;
  841.   int idx_base;
  842.  
  843.   if (idx < 6) /* analog jack */
  844.     {
  845.       idx_base = 0;
  846.       node_number = SIRIUS_ANALOG_NODE;
  847.     }
  848.   else /* digital jack */
  849.     {
  850.       idx_base = 6;
  851.       idx -= idx_base;
  852.       node_number = (idx % 2 == 0) ? 
  853.         SIRIUS_DIGITAL1_NODE : SIRIUS_DIGITAL2_NODE;
  854.     }
  855.  
  856.   if (ret_idx_base) *ret_idx_base = idx_base;
  857.   return node_number;
  858. }
  859.  
  860. int siriusconfigurepath(IJhandle me, int idx,
  861.                         VLNode source_node, VLNode drain_node, VLPath path,
  862.                         int node_number, int *ret_idx)
  863. {
  864.   VLControlValue val;
  865.   int returned_idx;
  866.   int idx_base=-1;
  867.  
  868.   /* -- compute idx_base if idx != VL_ANY */
  869.   if (idx != VL_ANY)
  870.     {
  871.       node_number = siriusmapidx(me, idx, &idx_base);
  872.       assert(node_number >= 0);
  873.       assert(idx_base >= 0);
  874.       idx -= idx_base;
  875.     }
  876.  
  877.   /* -- perform node-number-specific operations */
  878.   switch (node_number)
  879.     {
  880.     case SIRIUS_DIGITAL1_NODE:
  881.     case SIRIUS_DIGITAL2_NODE:
  882.       if (idx == VL_ANY)
  883.         {
  884.           idx_base = 6;
  885.  
  886.           if (vlGetControl(me->svr, path, source_node, VL_FORMAT, &val) < 0)
  887.             { vlDestroyPath(me->svr, path); return -1; }
  888.  
  889.           switch (val.intVal)
  890.             {
  891.             case VL_FORMAT_DIGITAL_COMPONENT:
  892.               returned_idx=0; break;
  893.             case VL_FORMAT_DIGITAL_COMPONENT_DUAL:        
  894.               returned_idx=2; break;
  895.             case VL_FORMAT_DIGITAL_COMPONENT_SERIAL:      
  896.               returned_idx=4; break;
  897.             case VL_FORMAT_DIGITAL_COMPONENT_DUAL_SERIAL: 
  898.               returned_idx=6; break;
  899.             }
  900.  
  901.           if (node_number == SIRIUS_DIGITAL2_NODE)
  902.             returned_idx += 1;
  903.         }
  904.       else
  905.         {
  906.           returned_idx = idx;
  907.           
  908.           if (idx == 0 || idx == 1) /* parallel 4:2:2:4 */
  909.             val.intVal = VL_FORMAT_DIGITAL_COMPONENT;
  910.           if (idx == 2 || idx == 3) /* parallel 4:4:4:4 */
  911.             val.intVal = VL_FORMAT_DIGITAL_COMPONENT_DUAL;
  912.           if (idx == 4 || idx == 5) /* serial 4:2:2:4 */
  913.             val.intVal = VL_FORMAT_DIGITAL_COMPONENT_SERIAL;
  914.           if (idx == 6 || idx == 7) /* serial 4:4:4:4 */
  915.             val.intVal = VL_FORMAT_DIGITAL_COMPONENT_DUAL_SERIAL;
  916.           
  917.           if (vlSetControl(me->svr, path, source_node, VL_FORMAT, &val) < 0)
  918.             { vlDestroyPath(me->svr, path); return -1; }
  919.         }
  920.       break;
  921.     case SIRIUS_ANALOG_NODE:
  922.       if (idx == VL_ANY)
  923.         {
  924.           idx_base = 0;
  925.  
  926.           if (vlGetControl(me->svr, path, source_node, VL_FORMAT, &val) < 0)
  927.             { vlDestroyPath(me->svr, path); return -1; }
  928.  
  929.           switch (val.intVal)
  930.             {
  931.             case VL_FORMAT_RGB:       returned_idx = 0; break;
  932.             case VL_FORMAT_SMPTE_YUV: returned_idx = 1; break;
  933.             case VL_FORMAT_BETACAM:   returned_idx = 2; break;
  934.             case VL_FORMAT_MII:       returned_idx = 3; break;
  935.             case VL_FORMAT_COMPOSITE: returned_idx = 4; break;
  936.             case VL_FORMAT_SVIDEO:    returned_idx = 5; break;
  937.             }
  938.         }
  939.       else
  940.         {
  941.           returned_idx = idx;
  942.  
  943.           switch (idx)
  944.             {
  945.             case 0: val.intVal = VL_FORMAT_RGB; break;
  946.             case 1: val.intVal = VL_FORMAT_SMPTE_YUV; break;
  947.             case 2: val.intVal = VL_FORMAT_BETACAM; break;
  948.             case 3: val.intVal = VL_FORMAT_MII; break;
  949.             case 4: val.intVal = VL_FORMAT_COMPOSITE; break;
  950.             case 5: val.intVal = VL_FORMAT_SVIDEO; break;
  951.             }
  952.           
  953.           if (vlSetControl(me->svr, path, source_node, VL_FORMAT, &val) < 0)
  954.             { vlDestroyPath(me->svr, path); return -1; }
  955.         }
  956.       break;
  957.     }
  958.       
  959.   assert(idx_base != -1);
  960.   if (ret_idx) *ret_idx = returned_idx + idx_base;
  961.   return 0;
  962. }
  963.  
  964. int siriusisjackcontrol(IJhandle me, VLControlType type)
  965. {
  966.   return (type==VL_FORMAT);
  967. }
  968.  
  969. ijdevice siriusdev = 
  970. { siriussetup, siriusgetjackname, 
  971.   siriusmapidx, siriusconfigurepath, 
  972.   siriusisjackcontrol, NULL };
  973.  
  974. /* devicename ---------------------------------------------------------- */
  975.  
  976. ijdevice *vldevname_to_ijdevice(char *vl_device_name)
  977. {
  978.   if (!strcmp(vl_device_name, "vino"))
  979.     return &vinodev;
  980.   else if (!strcmp(vl_device_name, "ev1"))
  981.     return &ev1dev;
  982.   else if (!strcmp(vl_device_name, "impact"))
  983.     return &impactdev;
  984.   else if (!strcmp(vl_device_name, "Sirius"))
  985.     return &siriusdev;
  986.   else
  987.     return NULL;
  988. }
  989.  
  990. /* API ------------------------------------------------------------- */
  991.  
  992. IJhandle ijOpenHandle(VLServer svr,
  993.                       VLDev device,
  994.                       VLNode drain_node)
  995. {
  996.   IJhandle me = malloc(sizeof(_IJhandle));
  997.   
  998.   if (!me) return NULL;
  999.  
  1000.   me->svr = svr;
  1001.   me->device = device;
  1002.  
  1003.   /* --- get a specific device */
  1004.  
  1005.   if (me->device == VL_ANY)
  1006.     {
  1007.       VLNode src_node;
  1008.       VLPath path;
  1009.       /* the VL is SO ANNOYING!! the only way to determine which device
  1010.        * would be used is to create an actual path!
  1011.        */
  1012.       if ((src_node = vlGetNode(me->svr, VL_SRC, VL_VIDEO, VL_ANY)) < 0)
  1013.         { free(me); return NULL; }
  1014.       if ((path = vlCreatePath(me->svr, VL_ANY, src_node, drain_node)) < 0)
  1015.         { free(me); return NULL; }
  1016.       if (vlSetupPaths(me->svr, (VLPathList)&path, 1, 
  1017.                        VL_READ_ONLY, VL_READ_ONLY) < 0)
  1018.         { free(me); return NULL; }
  1019.       if ((me->device = vlGetDevice(me->svr, path)) < 0)
  1020.         { free(me); return NULL; }
  1021.       if (vlDestroyPath(me->svr, path) < 0)
  1022.         { free(me); return NULL; }
  1023.     }
  1024.   assert(me->device != VL_ANY);
  1025.  
  1026.   /* --- map VL device to IJ device */
  1027.  
  1028.   me->ijd = NULL;
  1029.   {
  1030.     int dv;
  1031.     VLDevList devlist;
  1032.     if (vlGetDeviceList(me->svr, &devlist) < 0)
  1033.       { free(me); return NULL; }
  1034.     for (dv=0; dv < (int)devlist.numDevices; dv++)
  1035.       {
  1036.         if (devlist.devices[dv].dev == me->device)
  1037.           {
  1038.             me->ijd = vldevname_to_ijdevice(devlist.devices[dv].name);
  1039.             break;
  1040.           }
  1041.       }
  1042.     /* you are not supposed to free a VLDevList */
  1043.   }
  1044.   if (!me->ijd)  { free(me); return NULL; }
  1045.  
  1046.   /* --- do device-specific setup (inventory etc.) */
  1047.  
  1048.   me->num_jacks = -1;
  1049.   me->device_name = NULL;
  1050.  
  1051.   if (!(*me->ijd->setup)(me, drain_node))  /* this will set me->num_jacks */
  1052.     {
  1053.       free(me);
  1054.       return NULL;
  1055.     }
  1056.  
  1057.   assert(me->num_jacks != -1);
  1058.   assert(me->device_name != NULL);
  1059.   
  1060.   return me;
  1061. }
  1062.  
  1063. void ijCloseHandle(IJhandle me)
  1064. {
  1065.   if (me->ijd->teardown)
  1066.     (*me->ijd->teardown)(me);
  1067. }
  1068.  
  1069. char *ijGetDeviceName(IJhandle me)
  1070. {
  1071.   return me->device_name;
  1072. }
  1073.  
  1074. int ijGetVLDev(IJhandle me)
  1075. {
  1076.   return me->device;
  1077. }
  1078.  
  1079. int ijGetNumJacks(IJhandle me)
  1080. {
  1081.   return me->num_jacks;
  1082. }
  1083.  
  1084. char *ijGetJackName(IJhandle me, int idx)
  1085. {
  1086.   if (idx < 0 || idx >= me->num_jacks)
  1087.     return NULL;
  1088.  
  1089.   return (*me->ijd->getjackname)(me, idx);
  1090. }
  1091.  
  1092. int ijGetNodeNumber(IJhandle me, int idx)
  1093. {
  1094.   int node_number;
  1095.  
  1096.   if (idx != VL_ANY && (idx < 0 || idx >= me->num_jacks))
  1097.     return -1;
  1098.  
  1099.   /* -- map idx to node number, or find default node for idx==VL_ANY */
  1100.   if (idx == VL_ANY)
  1101.     node_number = getdefaultsource(me);
  1102.   else
  1103.     node_number = (*me->ijd->mapidx)(me, idx, NULL);
  1104.  
  1105.   return node_number;
  1106. }
  1107.  
  1108. int ijConfigurePath(IJhandle me, int idx,
  1109.                     VLNode source_node, VLNode drain_node, VLPath path,
  1110.                     int node_number, int *ret_idx)
  1111. {
  1112.   if (idx != VL_ANY && (idx < 0 || idx >= me->num_jacks))
  1113.     return -1;
  1114.  
  1115.   if (node_number < 0)
  1116.     return -1;
  1117.   
  1118.   return (*me->ijd->configurepath)(me, idx,
  1119.                                    source_node, drain_node, path,
  1120.                                    node_number, ret_idx);
  1121. }
  1122.  
  1123. int ijDoesControlAffectInputJack(IJhandle me, VLControlType type) 
  1124. {
  1125.   return (*me->ijd->isjackcontrol)(me, type);
  1126. }
  1127.